/*
 * link_list.h
 *
 *  Created on: Mar 26, 2012
 *      Author: lin
 */

#ifndef LINK_LIST_H_
#define LINK_LIST_H_

#include "def/defs.h"
#include "zmalloc/zmalloc.h"

typedef struct link_list_node {
    struct link_list_node *prev;
    struct link_list_node *next;
    mixed_t val;
} link_list_node_t;

typedef struct {
    link_list_node_t *next;
    int32_t reverse;
} link_list_iter_t;

typedef struct {
    mixed_t_dup_fn dup_fn;
    mixed_t_free_fn free_fn;
    mixed_t_match_fn match_fn;

    link_list_node_t *head;
    link_list_node_t *tail;
    int32_t size;
} link_list_t;

static inline link_list_t * link_list_new(void) {
    link_list_t* list = zcalloc(sizeof(link_list_t));
    return list;
}

void link_list_clean(link_list_t *list);

static inline void link_list_free(link_list_t *list) {
    link_list_clean(list);
    zfree(list);
}

link_list_t* link_list_add_head(link_list_t *list, mixed_t val);
link_list_t* link_list_add_tail(link_list_t *list, mixed_t val);

link_list_t* link_list_set(link_list_t *list, int32_t idx, mixed_t val);
mixed_t link_list_get(const link_list_t *list, int32_t index);
int32_t link_list_index(const link_list_t *list, mixed_t match);
link_list_t* link_list_remove(link_list_t *list, int32_t idx);

link_list_iter_t *link_list_iter_new(const link_list_t *list, int32_t reverse);
void link_list_rewind(const link_list_t *list, link_list_iter_t *iter,
        int32_t reverse);
mixed_t link_list_next(link_list_iter_t *iter, int* hasnext);
static inline void link_list_iter_free(link_list_iter_t *iter) {
    zfree(iter);
}

link_list_t *link_list_dup(const link_list_t *orig);

link_list_t link_list_rotate(link_list_t *list);

int32_t link_list_to_array(const link_list_t *list, mixed_t * array,
        int32_t sizeto);

#define link_list_size(list) (list)->size
#define link_list_head(list) (list)->head
#define link_list_tail(list) (list)->tail
#define link_list_node_prev(node) (node)->prev
#define link_list_node_next(node) (node)->next

#define link_list_dup_fn_set(list,dup) (list)->dup_fn=dup
#define link_list_free_fn_set(list,free) (list)->free_fn=free;
#define link_list_match_fn_set(list,match) (list)->match_fn=match

#define link_list_dup_fn_get(list) (list)->dup_fn
#define link_list_free_fn_get(list) (list)->free_fn
#define link_list_match_fn_get(list) (list)->match_fn

#endif /* LINK_LIST_H_ */
